/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package h2x;

import elaborate.h2x.parser.XHTMLUtil;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

/**
 *
 * @author lendle
 */
public class Test2 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        // TODO code application logic here
        Document doc = XHTMLUtil.fromHTML(new File("example1.xhtml").toURI().toURL(), "utf-8");

        XPath xpath = XPathFactory.newInstance().newXPath();
        
        Map<Element, Element> enclosingMap=new HashMap<Element, Element>();
        createTransformTree(null, doc.getDocumentElement(), enclosingMap);
        Map<Element, Element> transformingMap=new HashMap<Element, Element>();
        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder docBuilder=dbf.newDocumentBuilder();
        Document newDoc=docBuilder.newDocument();
        transform(doc.getDocumentElement(), enclosingMap, transformingMap, newDoc);
//        System.out.println(newDoc);
//        Iterator<Map.Entry<Element, Element>> it=enclosingMap.entrySet().iterator();
//        while(it.hasNext()){
//            Map.Entry<Element, Element> entry=it.next();
//            System.out.println(entry.getKey()+"_"+entry.getKey().getAttributeNS("h2x", "def") +":"+entry.getValue()+"_"+entry.getValue().getAttributeNS("h2x", "def"));
//        }
        Transformer tf=TransformerFactory.newInstance().newTransformer();
        tf.transform(new DOMSource(newDoc), new StreamResult(System.out));
    }
    
    private static void transform(Element rootElement, Map<Element, Element> enclosingMap, Map<Element, Element> transformingMap, Document newDoc){
        Attr defAttr = rootElement.getAttributeNodeNS("h2x", "def");
        if (defAttr != null) {
            Element contextSourceParentNode=enclosingMap.get(rootElement);
            Node contextTargetParentnode=null;
            if(contextSourceParentNode==null){
                //root
                contextTargetParentnode=newDoc;
            }
            else{
                contextTargetParentnode=transformingMap.get(contextSourceParentNode);
                if(contextTargetParentnode==null){
                    //has not been converted yet
                    transform(contextSourceParentNode, enclosingMap, transformingMap, newDoc);
                }
            }
            
            String defValue=defAttr.getValue();
            if("text()".equals(defValue)){
                Text text=newDoc.createTextNode(rootElement.getTextContent());
                contextTargetParentnode.appendChild(text);
            }
            else{
                QName qName=parseQName(defValue);
                Element newElement=newDoc.createElementNS(qName.getNamespaceURI(), qName.getLocalPart());
                transformingMap.put(rootElement, newElement);
                contextTargetParentnode.appendChild(newElement);
            }
        }
        Node childNode = rootElement.getFirstChild();
        while (childNode != null) {
            if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                transform((Element) childNode, enclosingMap, transformingMap, newDoc);
            }
            childNode = childNode.getNextSibling();
        }
    }
    
    /**
     * convert a {...}xxx string into a QName instance
     * @param qNameString
     * @return 
     */
    private static QName parseQName(String qNameString){
        int index=qNameString.lastIndexOf("}");
        if(index!=-1){
            int index2=qNameString.indexOf("{");
            String namespaceURI=qNameString.substring(index2+1, index);
            String localName=qNameString.substring(index+1);
            return new QName(namespaceURI, localName);
        }
        else{
            return new QName(qNameString);
        }
    }
    
    private static void createTransformTree(Element nearestEnclosingRoot, Element rootElement, Map<Element, Element> enclosingMap) {
        Attr defAttr = rootElement.getAttributeNodeNS("h2x", "def");
        if (defAttr != null) {
            if (nearestEnclosingRoot != null) {
                enclosingMap.put(rootElement, nearestEnclosingRoot);
            }
            nearestEnclosingRoot = rootElement;
        }
        Node childNode = rootElement.getFirstChild();
        while (childNode != null) {
            if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                createTransformTree(nearestEnclosingRoot, (Element) childNode, enclosingMap);
            }
            childNode = childNode.getNextSibling();
        }
    }
}
